#include "hv_chip_Config.h"
#include "hv_boot_Common.h"


#define phy_base_addr (0x11018000)
#define ctr_base_addr (0x11014000)

#define mc_printf(...)
#define check_list_print(...)
#define uint32_t unsigned int
#define AHB_CHECK_PHY(addr, mask, need)\
do                              \
{                               \
    while ((BOOT_RD32(addr+0x11018000)&mask) != need)  \
    {                           \
        Hv_Boot_Wait_Us(1);     \
    }                           \
}                               \
while(0)

#define AHB_CHECK_CTRL(addr, mask, need)\
do                              \
{                               \
    while ((BOOT_RD32(addr+0x11014000)&mask) != need)  \
    {                           \
        Hv_Boot_Wait_Us(1);     \
    }                           \
}                               \
while(0)

#define ca7_write(addr, value) (*(volatile unsigned int*)(addr) = (value))
#define AHB_WR_PHY(addr, value)  (*(volatile unsigned int*)(addr+0x11018000) = (value))
#define AHB_WR_CTRL(addr, value) (*(volatile unsigned int*)(addr+0x11014000) = (value))
// #define AHB_WR_PHY(addr, value)  (*(volatile unsigned int*)(addr+0x11018000) = (value));Hv_Boot_Wait_Us(10000);Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> wr phy ");Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_WAR, addr);Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_WAR, value)
// #define AHB_WR_CTRL(addr, value) (*(volatile unsigned int*)(addr+0x11014000) = (value));Hv_Boot_Wait_Us(10000);Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> wr ctr ");Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_WAR, addr);Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_WAR, value)
#define AHB_RD_PHY(addr)    (*(volatile unsigned int*)(addr+0x11018000))
#define BITSET(addr, end, start, value) do { \
    volatile uint32_t *pReg = (volatile uint32_t *)(addr); \
    uint32_t uTemp = *pReg; \
    const uint32_t uWidth = (end) - (start) + 1; \
    uint32_t uMask = (uWidth == 32) ? 0xFFFFFFFF : ((1U << uWidth) - 1); \
    uint32_t uSetVal = (value); \
    \
    if (uSetVal > uMask) { \
        /* 这里使用您系统的日志函数，例如：HV_LOGV("value err") */ \
        break; /* 跳过本次设置 */ \
    } \
    \
    uMask <<= (start); \
    uSetVal <<= (start); \
    uTemp = (uTemp & ~uMask) | (uSetVal & uMask); \
    *pReg = uTemp; \
} while(0)

unsigned int val_read_softeyes(unsigned int cons, unsigned int end_bitpos, unsigned int start_bitpos)
{
	unsigned int bit_num = end_bitpos - start_bitpos + 1;
	unsigned int bit_mask = (1 << bit_num) - 1;

	if (bit_num == 32) {
		return cons;
	} else {
		cons &= (bit_mask << start_bitpos);
		return (cons >> start_bitpos);
	}
}

// = BITSET()
void ddr_reg_write_softeyes(unsigned long addr, unsigned long end_bitpos, unsigned long start_bitpos, unsigned long value)
{
	unsigned long bit_num = end_bitpos - start_bitpos + 1;
	unsigned long bit_mask = (1 << bit_num) - 1;
	unsigned long reg_data = AHB_RD_PHY(addr);

	reg_data &= ~(bit_mask << start_bitpos);
	reg_data |= ((value & bit_mask) << start_bitpos);

	AHB_WR_PHY(addr,reg_data);
}

void vref_wr(unsigned int val)
{
	//l16 vref
	ddr_reg_write_softeyes(phy_base_addr+0x6bc,7,7,val_read_softeyes(val,0,0));
	ddr_reg_write_softeyes(phy_base_addr+0x6bc,8,8,val_read_softeyes(val,1,1));
	ddr_reg_write_softeyes(phy_base_addr+0x6bc,9,9,val_read_softeyes(val,2,2));
	ddr_reg_write_softeyes(phy_base_addr+0x6bc,10,10,val_read_softeyes(val,3,3));
	ddr_reg_write_softeyes(phy_base_addr+0x6bc,11,11,val_read_softeyes(val,4,4));
	
	//h16 vref
	ddr_reg_write_softeyes(phy_base_addr+0x698,25,25,val_read_softeyes(val,0,0));
	ddr_reg_write_softeyes(phy_base_addr+0x698,26,26,val_read_softeyes(val,1,1));
	ddr_reg_write_softeyes(phy_base_addr+0x698,27,27,val_read_softeyes(val,2,2));
	ddr_reg_write_softeyes(phy_base_addr+0x698,28,28,val_read_softeyes(val,3,3));
	ddr_reg_write_softeyes(phy_base_addr+0x698,29,29,val_read_softeyes(val,4,4));
}

// to_do force reset=0
// @(posedge test_top.SystemReset);

//=======================================================================
// LPDDR3 DDR 内存控制器和PHY初始化 @1866Mbps
// 本文件实现了LPDDR3 DDR内存的完整初始化流程，包括：
// 1. PLL时钟设置
// 2. DDR控制器和PCU配置  
// 3. DDR PHY设置
// 4. DDR训练流程（CA训练、Gating训练、写电平训练、读电平训练）
//=======================================================================


#define ENABLE_TEST01

#define SLICE0_RD_DLL (0x48)
#define SLICE1_RD_DLL (0x48)
#define SLICE2_RD_DLL (0x48)
#define SLICE3_RD_DLL (0x48)

#define SLICE0_WR_DLL (0x38)
#define SLICE1_WR_DLL (0x38)
#define SLICE2_WR_DLL (0x38)
#define SLICE3_WR_DLL (0x38)

#define SLICE0_GATE_DLL (0x10)
#define SLICE1_GATE_DLL (0x10)
#define SLICE2_GATE_DLL (0x10)
#define SLICE3_GATE_DLL (0x10)

#define SLICE0_GATE_UI_DELAY (1)
#define SLICE1_GATE_UI_DELAY (1)
#define SLICE2_GATE_UI_DELAY (1)
#define SLICE3_GATE_UI_DELAY (1)

#define SLICE0_GATE_CLK_DELAY (1)
#define SLICE1_GATE_CLK_DELAY (1)
#define SLICE2_GATE_CLK_DELAY (1)
#define SLICE3_GATE_CLK_DELAY (1)

#define DQ_VREF (7)
// void odt_ds_init() {
//     const odt_slice0 = 0x99<< 1 | 0x1;
//     const odt_slice1 = 0x99<< 1 | 0x1;
//     const odt_slice2 = 0x99<< 1 | 0x1;
//     const odt_slice3 = 0x99<< 1 | 0x1;
//     const dsel_slice0 = 0x68;
//     const dsel_slice1 = 0x68;
//     const dsel_slice2 = 0x68;
//     const dsel_slice3 = 0x68;
//     uint16_t src[8] = {odt_slice3, dsel_slice3, odt_slice2, dsel_slice2, odt_slice1, dsel_slice1, odt_slice0, dsel_slice0};

//     uint64_t hi64 = 0;
//     uint64_t lo64 = 0;
//     unsigned int rdata;

//     for (int i = 0; i < 8; ++i) {
//         int total_shift = 9 * (7 - i);
//         uint64_t val = src[i] & 0x1FFULL;
//         if (total_shift >= 64) {
//             hi64 |= val << (total_shift - 64);
//         } else {
//             if (total_shift + 9 <= 64) {
//                 lo64 |= val << total_shift;
//             } else {
//                 int shift_lo = total_shift;
//                 int shift_hi = 64 - total_shift;
//                 lo64 |= val << shift_lo;
//                 hi64 |= val >> shift_hi;
//             }
//         }
//     }
//     uint8_t high8 = (hi64 & 0xFFULL);
//     uint32_t mid32 = ((lo64 >> 32) & 0xFFFFFFFFUL);
//     uint32_t low32 = (lo64 & 0xFFFFFFFFUL);

//     AHB_WR_PHY(0x000006a0, low32); // 0
//     AHB_WR_PHY(0x000006a4, mid32); // 1
//     rdata = (AHB_RD_PHY(0x000006a4) & 0xffffff00) | high8;
//     AHB_WR_PHY(0x000006a8, rdata); // 2
// }
// void test01(void) {
//     int gate_cfg;
//     int fine_delay;
//     int rdata;

//     for (int gate_dll = 0; gate_dll < 0x7ff; gate_dll = gate_dll + 0x10) {
//         gate_cfg = (gate_dll & 0x7ff) >> 8;
//         fine_delay = gate_dll & 0xff;
//         mc_printf("gate_cfg : %x", gate_cfg);
//         mc_printf("fine_delay : %x", fine_delay);

//         for (int slice_seq = 0; slice_seq <= 3; slice_seq++) {
//             rdata = AHB_RD_PHY(0X00000414 + slice_seq * 0x80);
//             rdata = (rdata & 0x00ffffff) | (fine_delay << 24);
//             AHB_WR_PHY(0x00000414 + slice_seq * 0x80, rdata);
//             rdata = AHB_RD_PHY(0x00000408 + slice_seq * 0x80);
//             rdata = (rdata & 0xfffffff8) | gate_cfg;
//             AHB_WR_PHY(0x00000408 + slice_seq * 0x80, rdata);
//         }
//         AHB_WR_PHY(0x2200, 0x10);
//         rdata = AHB_RD_DRAM(0x00000000);

//         for (int slice_seq = 0; slice_seq <= 3; slice_seq++) {
//             rdata = AHB_RD_PHY(0X00000424 + slice_seq * 0x80);
//             rdata = (rdata & 0x00070000) >> 16;
//             mc_printf("slice %x gate_dqs_count : %x", slice_seq, rdata);
//             rdata = AHB_RD_PHY(0x00000450 + slice_seq * 0x80);
//             rdata = (rdata & 0x00004000) >> 14;
//             mc_printf("slice %x gate_sample_dqs : %x", slice_seq, rdata);
//         }
//     }
// }

// uint32_t AHB_RD_DRAM(uint32_t addr) {
//     // AHB DRAM base: 0x40000000
//     return reg_read(0x00000000+addr);
// }
#define PLL_REAL
 #define sg94
    // #define POST_SIM_PATCH
void lpddr3_init() {
    //-----------------------------------------------------------------------
    // 局部变量声明
    //-----------------------------------------------------------------------
    uint32_t rdata;
    uint32_t wr_dqs;

    int ddr_freq = 2133;
    int lpddr3_gating_train = 0; // 正常跑的时候它应当是 0 因为它的状态机给出的数据不够准确
    int lpddr3_wrlvl_train = 1;
    int lpddr3_rdlvl_train = 0;
    int lpddr3_ca_train = 0;

    // RESET: 11015130 = 0xFFFFEDFE

    BITSET(0x11015130, 0, 0, 0);
    BITSET(0x11015130, 9, 9, 0);
    BITSET(0x11015130, 8, 8, 0);
    BITSET(0x11015130, 8, 8, 1);
    BITSET(0x11015130, 12, 12, 0);
    // ca7_write(0x11015130, 0xFFFFEDFE);

    //=======================================================================
    // 第一阶段：PLL时钟设置 @1866Mbps
    // 配置DDR相关的PLL时钟参数，为后续DDR控制器和PHY工作建立时钟基础
    //=======================================================================

#ifdef PLL_REAL
    AHB_WR_PHY(0x1008, 0x00000000); // PLL_RST

    if (ddr_freq == 1600) {
        // enze  AHB_WR_PHY(0x1000, (0x0000003f & 2) << 26 | (0x00000007 & 1) << 23 | (0x00000007 & 4) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 237) << 3 | (0x00000007 & 6) << 0);
        AHB_WR_PHY(0x1000, (0x0000003f & 2) << 26 | (0x00000007 & 1) << 23 | (0x00000007 & 4) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 237) << 3 | (0x00000007 & 6) << 0);
    } else if (ddr_freq == 2133) {
        AHB_WR_PHY(0x1000, (0x0000003f & 4) << 26 | (0x00000007 & 1) << 23 | (0x00000007 & 2) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 316) << 3 | (0x00000007 & 6) << 0);
    } else if (ddr_freq == 2400) {
        AHB_WR_PHY(0x1000, (0x0000003f & 8) << 26 | (0x00000007 & 1) << 23 | (0x00000007 & 2) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 710) << 3 | (0x00000007 & 6) << 0);
    } else if (ddr_freq == 3200) {
        AHB_WR_PHY(0x1000, (0x0000003f & 6) << 26 | (0x00000007 & 1) << 23 | (0x00000007 & 2) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 709) << 3 | (0x00000007 & 6) << 0);
    } else if (ddr_freq == 150) {
        AHB_WR_PHY(0x1000, (0x0000003f & 3) << 26 | (0x00000007 & 4) << 23 | (0x00000007 & 7) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 234) << 3 | (0x00000007 & 6) << 0);
    } else if (ddr_freq == 54) {
        AHB_WR_PHY(0x1000, (0x0000003f & 3) << 26 | (0x00000007 & 4) << 23 | (0x00000007 & 7) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 234) << 3 | (0x00000007 & 4) << 0);
    }

    AHB_WR_PHY(0x100c, (0x0000003f & 8) << 26 | (0x00000007 & 1) << 23 | (0x00000007 & 2) << 20 | (0x0000001f & 0) << 15 | (0x00000fff & 710) << 3 | (0x00000007 & 6) << 0);

    AHB_WR_PHY(0x1008, 0x00000010);             // PLL_RST
    AHB_WR_PHY(0x1008, 0x00000000);             // PLL_RST
    AHB_CHECK_PHY(0x1000, 0x00080000, 0x80000); // PLL_DONE
#endif

    // ca7_write(0x11015130, 0xFFFFEDFF);
    BITSET(0x11015130, 0, 0, 1);
    BITSET(0x11015130, 9, 9, 0);
    BITSET(0x11015130, 8, 8, 1);
    BITSET(0x11015130, 12, 12, 0);

    // refdiv p2  p1        fbdiv
    // {6'd2,3'd1,3'd4,5'd0,12'd237,30x6} 1600,
    // {6'd4,3'd1,3'd2,5'd0,12'd316,30x6} 2133
    // {6'd8,3'd1,3'd2,5'd0,12'd711,30x6} 2400

    //=======================================================================
    // 第二阶段：DDR控制器和PCU配置 @1866Mbps
    // 设置DDR控制器寄存器和Power Control Unit(PCU)参数
    // 包括ZQ校准、时序参数、模式寄存器初始化等配置
    //=======================================================================
    //************************************
    // init step2 DDR controller & DDR PCU
    //             setting @1866Mbps
    //************************************

    //-----------------------------------------------------------------------
    // ZQ校准和主控制寄存器配置
    //-----------------------------------------------------------------------
    AHB_WR_PHY(0x00690, 30); // zq-calibration phy_pad_cal_ctrl

#ifdef x16bit_half_mode
    AHB_WR_CTRL(0x00000000, 0xc0041408); // MSTR
#else
    AHB_WR_CTRL(0x00000000, 0xc0040408); // MSTR
#endif

    //-----------------------------------------------------------------------
    // 基础控制寄存器配置
    //-----------------------------------------------------------------------
    AHB_WR_CTRL(0x00000010, 0x00007010);
    AHB_WR_CTRL(0x00000014, 0x00000000);
    AHB_WR_CTRL(0x00000034, 0x00402010);
    AHB_WR_CTRL(0x00000038, 0x01250003);
    AHB_WR_CTRL(0x000000d0, 0x40020003);
    AHB_WR_CTRL(0x000000d4, 0x00030000);

    //-----------------------------------------------------------------------
    // 模式寄存器初始化配置 (INIT3-INIT7)
    //-----------------------------------------------------------------------
#ifdef sg94
    AHB_WR_CTRL(0x000000dc, 0x0083001e); // INIT3 RL 16 WL 8  BL 8, mr1/mr2
#else
    AHB_WR_CTRL(0x000000dc, 0x0043001a); // INIT3 RL 12 WL 6  BL 8, mr1/mr2
#endif

    AHB_WR_CTRL(0x000000e0, 0x00100000); // INIT4 mr3
    AHB_WR_CTRL(0x000000e4, 0x00110004); // INIT5
    AHB_WR_CTRL(0x000000e8, 0x00000000); // INIT6
    AHB_WR_CTRL(0x000000ec, 0x00000000); // INIT7

    //-----------------------------------------------------------------------
    // DDR时序参数配置 (DRAMTMG0-DRAMTMG8)
    //-----------------------------------------------------------------------
    AHB_WR_CTRL(0x000000f0, 0x00000000);
    AHB_WR_CTRL(0x00000100, 0x10121112); // DRAMTMG0
    AHB_WR_CTRL(0x00000104, 0x00040819); // DRAMTMG1

#ifdef sg94
    AHB_WR_CTRL(0x00000108, 0x05070c0c); // DRAMTMG2 xxxxxxxxxxx rd2wr
#else
    AHB_WR_CTRL(0x00000108, 0x05070b0b); // DRAMTMG2 xxxxxxxxxxx rd2wr
#endif

     AHB_WR_CTRL(0x0000010c, 0x00500008);

#ifdef sg94
     AHB_WR_CTRL(0x00000110, 0x0d02060f);//  band width 【19：16】 tccd 06-07 is fixed
#else
    AHB_WR_CTRL(0x00000110, 0x0a02050d);
#endif

    AHB_WR_CTRL(0x00000114, 0x02020808);
    AHB_WR_CTRL(0x00000120, 0x03030802);
    AHB_WR_CTRL(0x000001c0, 0x00000001);
    AHB_WR_CTRL(0x00000124, 0x0002040c);
    AHB_WR_CTRL(0x0000013c, 0x00000001);

    //-----------------------------------------------------------------------
    // ZQ控制和DFI时序配置
    //-----------------------------------------------------------------------
    AHB_WR_CTRL(0x00000184, 0x02000070); // ZQCTL1

#ifdef sg94
    AHB_WR_CTRL(0x00000190, 0x06918108); // DFITMG0 xxx [5:0] wrlat [13:8] wdata, [22:16] rdata_en
#else
    // AHB_WR_CTRL(0x00000190, 0x068d8106); // DFITMG0 xxx [5:0] wrlat [13:8] wdata, [22:16] rdata_en
    AHB_WR_CTRL(0x00000190, 0x068d8106); // DFITMG0 xxx [5:0] wrlat [13:8] wdata, [22:16] rdata_en
    if (ddr_freq == 150) {
        AHB_WR_CTRL(0x00000190, 0x06858106);
    }
    if (ddr_freq == 54) {
        AHB_WR_CTRL(0x00000190, 0x068b8106);
    }
#endif

    AHB_WR_CTRL(0x00000194, 0x00080307);
    AHB_WR_CTRL(0x00000198, 0x07500020);
    AHB_WR_CTRL(0x000001a0, 0xe0400005); // enze 0826
    AHB_WR_CTRL(0x000001a4, 0x002e00c4);

#ifndef zq_cal
    AHB_WR_CTRL(0x000001a8, 0x00000000); // DFIUPD2
#else
    AHB_WR_CTRL(0x000001a8, 0x80000000); // DFIUPD2
#endif

    AHB_WR_CTRL(0x00000014, 0x00006cda);
    AHB_WR_CTRL(0x00000030, 0x00000000);
    AHB_WR_CTRL(0x00000050, 0x00211074);
    AHB_WR_CTRL(0x00000060, 0x00000000);
    AHB_WR_CTRL(0x00000064, 0x004000bb);
    AHB_WR_CTRL(0x000000c0, 0x00000004);
    AHB_WR_CTRL(0x00000180, 0x40a00028);
    AHB_WR_CTRL(0x00000198, 0x07500020);
    AHB_WR_CTRL(0x000001b0, 0x00000041);
    AHB_WR_CTRL(0x000001c4, 0x80000001);
    AHB_WR_CTRL(0x00000304, 0x00000000);
    AHB_WR_CTRL(0x0000030c, 0x00000000);
    AHB_WR_CTRL(0x0000036c, 0x00110011);
    AHB_WR_CTRL(0x00000240, 0x06000610);
    AHB_WR_CTRL(0x00000244, 0x00000001);
    AHB_WR_CTRL(0x00000490, 0x00000001);
    AHB_WR_CTRL(0x00000204, 0x00080808);
    AHB_WR_CTRL(0x00000210, 0x00001f1f);
    AHB_WR_CTRL(0x00000214, 0x07070707);
    AHB_WR_CTRL(0x00000218, 0x07070707);
    AHB_WR_CTRL(0x0000021c, 0x00000f0f);
    AHB_WR_CTRL(0x00000250, 0x00501b04);
    AHB_WR_CTRL(0x00000254, 0x000000fa);
    AHB_WR_CTRL(0x0000025c, 0x0f000bb8);
    AHB_WR_CTRL(0x00000264, 0x0f001388);
    AHB_WR_CTRL(0x0000026c, 0x0f001388);
    AHB_WR_CTRL(0x00000300, 0x00000000);
    AHB_WR_CTRL(0x00000320, 0x00000001);
    AHB_WR_CTRL(0x00000400, 0x00000101);
    AHB_WR_CTRL(0x00000404, 0x000051ff);
    AHB_WR_CTRL(0x00000494, 0x02100c07);
    AHB_WR_CTRL(0x00000408, 0x000051ff);



    AHB_WR_CTRL(0x00000204, 0x00070707);// jiongrui
    AHB_WR_CTRL(0x00000208, 0x00000000);
    AHB_WR_CTRL(0x0000020c, 0x1f000000);
    AHB_WR_CTRL(0x00000210, 0x00001f1f);
    AHB_WR_CTRL(0x00000214, 0x06060606);
    AHB_WR_CTRL(0x00000218, 0x0f0f0f06);
    AHB_WR_CTRL(0x0000021c, 0x00000000);
    AHB_WR_CTRL(0x00000050, 0x00211010); //close perbank 

    // to_do release reset
    // AHB_WR_CTRL(0x00000320, 0x00000001); // SW_DONE
    // 0x11015130 = 0xFFFFFFFF
    // ca7_write(0x11015130, 0xFFFFFFFF);
    BITSET(0x11015130, 0, 0, 1);
    BITSET(0x11015130, 9, 9, 1);
    BITSET(0x11015130, 8, 8, 1);
    BITSET(0x11015130, 12, 12, 1);

    //=======================================================================
    // 第三阶段：DDR PHY设置 @1866Mbps
    // 配置DDR PHY物理层参数，包括读写控制、ZQ校准、延迟设置等
    //=======================================================================
    //************************************
    // init step3 DDR PHY setting @1866Mbps
    //************************************

    //-----------------------------------------------------------------------
    // DDR PHY 字节0配置
    //-----------------------------------------------------------------------
    AHB_WR_PHY(0x00000400, 0x00600803 | (SLICE0_RD_DLL << 24 ));
    AHB_WR_PHY(0x00000404, 0x00c30815);
    AHB_WR_PHY(0x00000408, 0x100100d8 | SLICE0_GATE_CLK_DELAY  | (SLICE0_GATE_UI_DELAY << 29) ); // [7:5] gate err delay
    AHB_WR_PHY(0x0000040c, 0x10008102); // read ctrl
    AHB_WR_PHY(0x00000410, 0x1422000f);
    AHB_WR_PHY(0x00000414, 0x00000000 | SLICE0_RD_DLL | (SLICE0_WR_DLL << 8) | (SLICE0_GATE_DLL << 24));
    AHB_WR_PHY(0x00000428, 0x00000001);
    AHB_WR_PHY(0x0000042c, 0x030c30c1); // enze
    AHB_WR_PHY(0x00000430, 0x030c30c1);
    AHB_WR_PHY(0x00000438, 0x4b40f000); // enable [27] sw half cycle
    // AHB_WR_PHY(0x00000450, 0x80008000); // shift cycle
    // AHB_WR_PHY(0x00000450, 0x80808000); // shift cycle
    AHB_WR_PHY(0x00000450, 0xC0C08080); // shift cycle

    //-----------------------------------------------------------------------
    // DDR PHY 字节1配置
    //-----------------------------------------------------------------------
    AHB_WR_PHY(0x00000480, 0x00600803 | (SLICE1_RD_DLL << 24 ));
    AHB_WR_PHY(0x00000484, 0x00c30815);
    AHB_WR_PHY(0x00000488, 0x100100d8 | SLICE1_GATE_CLK_DELAY  | (SLICE1_GATE_UI_DELAY << 29) ); // [7:5] gate err delay
    AHB_WR_PHY(0x0000048c, 0x10008102); // read ctrl dqs_ie[9:7]  dq_ie[15:13]
    AHB_WR_PHY(0x00000490, 0x1422000f);
    AHB_WR_PHY(0x00000494, 0x00000000 | SLICE1_RD_DLL | (SLICE1_WR_DLL << 8) | (SLICE1_GATE_DLL << 24));
    AHB_WR_PHY(0x000004a8, 0x00000001);
    AHB_WR_PHY(0x000004ac, 0x030c30c3);
    AHB_WR_PHY(0x000004b0, 0x030c30c3);
    AHB_WR_PHY(0x000004b8, 0x4b40f000);
    // AHB_WR_PHY(0x00000480 + 0x50, 0x80008000); // shift cycle
    // AHB_WR_PHY(0x00000480 + 0x50, 0x80808000); // shift cycle
    AHB_WR_PHY(0x00000480 + 0x50, 0xC0C08080); // shift cycle

    //-----------------------------------------------------------------------
    // DDR PHY 字节2配置
    //-----------------------------------------------------------------------
    AHB_WR_PHY(0x00000500, 0x00600803 | (SLICE2_RD_DLL << 24 ));
    AHB_WR_PHY(0x00000504, 0x00c30815);
    AHB_WR_PHY(0x00000508, 0x100100d8 | SLICE2_GATE_CLK_DELAY  | (SLICE2_GATE_UI_DELAY << 29) ); // [7:5] gate err delay
    AHB_WR_PHY(0x0000050c, 0x10008102); // read ctrl
    AHB_WR_PHY(0x00000510, 0x1422000f);
    AHB_WR_PHY(0x00000514, 0x00000000 | SLICE2_RD_DLL | (SLICE2_WR_DLL << 8) | (SLICE2_GATE_DLL << 24));
    AHB_WR_PHY(0x00000528, 0x00000001);
    AHB_WR_PHY(0x0000052c, 0x030c30c3);
    AHB_WR_PHY(0x00000530, 0x030c30c3);
    AHB_WR_PHY(0x00000538, 0x4b40f000);
    // AHB_WR_PHY(0x00000500 + 0x50, 0x80008000); // shift cycle
    AHB_WR_PHY(0x00000500 + 0x50, 0xc0C08080); // shift cycle

    //-----------------------------------------------------------------------
    // DDR PHY 字节3配置
    //-----------------------------------------------------------------------
    AHB_WR_PHY(0x00000580, 0x00600803 | (SLICE3_RD_DLL << 24 ));
    AHB_WR_PHY(0x00000584, 0x00c30815);
    AHB_WR_PHY(0x00000588, 0x100100d8 | SLICE3_GATE_CLK_DELAY |(SLICE3_GATE_UI_DELAY << 29)); // [7:5] gate err delay
    AHB_WR_PHY(0x0000058c, 0x10008102); // read ctrl
    AHB_WR_PHY(0x00000590, 0x1422000f);
    AHB_WR_PHY(0x00000594, 0x00000000 | SLICE3_RD_DLL | (SLICE3_WR_DLL << 8) | (SLICE3_GATE_DLL << 24));
    AHB_WR_PHY(0x000005a8, 0x00000001);
    AHB_WR_PHY(0x000005ac, 0x030c10c1);
    AHB_WR_PHY(0x000005b0, 0x030c30c1);
    AHB_WR_PHY(0x000005b8, 0x4b40f000);
    // AHB_WR_PHY(0x00000580 + 0x50, 0x80008000); // shift cycle
    // AHB_WR_PHY(0x00000580 + 0x50, 0x80808000); // shift cycle
    AHB_WR_PHY(0x00000580 + 0x50, 0xC0C08080); // shift cycle

    AHB_WR_PHY(0x00000600, 0x08130813);
    AHB_WR_PHY(0x00000604, 0x08150815);
    AHB_WR_PHY(0x00000608, 0x800100c8); // [31] close sw dqs phase bypass for half cycle shift
    AHB_WR_PHY(0x0000060c, 0x00000066);
    AHB_WR_PHY(0x00000610, 0x0e12000f);
    AHB_WR_PHY(0x00000614, 0x00004040);
    AHB_WR_PHY(0x00000628, 0x00000000);
    AHB_WR_PHY(0x0000062c, 0x0000818a); // [12] en sw half cycle
    AHB_WR_PHY(0x00000638, 0x4240f000);

    AHB_WR_PHY(0x00000680, 0x0600580a); // [11] ddr_sel

    if (ddr_freq == 54) {
        AHB_WR_PHY(0x00000410, 0x0812000f); // [28:25] pop dly
        AHB_WR_PHY(0x00000490, 0x0812000f); // [28:25] pop dly
        AHB_WR_PHY(0x00000510, 0x0812000f); // [28:25] pop dly
        AHB_WR_PHY(0x00000590, 0x0812000f); // [28:25] pop dly

        AHB_WR_PHY(0x00000454, 0x00000003); // [3:0] rd dly
        AHB_WR_PHY(0x000004d4, 0x00000003); // [3:0] rd dly
        AHB_WR_PHY(0x00000554, 0x00000003); // [3:0] rd dly
        AHB_WR_PHY(0x000005d4, 0x00000003); // [3:0] rd dly

        AHB_WR_PHY(0x00000680, 0x06005804); // [3:0] read data valid dly

       AHB_WR_PHY(0x00000450, 0x80c88000); // [23:22] shift cycle  enze 0828 modified to tccd 
       AHB_WR_PHY(0x000004d0, 0x80c88000); // [23:22] shift cycle  enze 0828 modified to tccd 
       AHB_WR_PHY(0x00000550, 0x80c88000); // [23:22] shift cycle  enze 0828 modified to tccd 
       AHB_WR_PHY(0x000005d0, 0x80c88000); // [23:22] shift cycle  enze 0828 modified to tccd 
    }

    AHB_WR_PHY(0x00000684, 0x00004040); // param_address_command_bdl_ctrl_reg
    AHB_WR_PHY(0x00000688, 0x01001320); // [4:3] ca pat num [25:24] ca step

    //-----------------------------------------------------------------------
    // DDR PHY ZQ校准配置
    //-----------------------------------------------------------------------
    // AHB_WR_PHY(0x00000690, 0x97b50000);
    // AHB_WR_PHY(0x00000690, 0x0000001E); // zq
    AHB_WR_PHY(0x00000694, 0x00889988);
    // AHB_WR_PHY(0x00000698, 0x10000028);

#ifndef POST_SIM
    // pad cfg

    //*******************
    // ZQ Cal ctrl config
    //******************
    AHB_WR_PHY(0x00000698, 0x100C9B08); // cal ctrl reg0
    AHB_WR_PHY(0x000006bc, 0x80000000); // 7 [31]
    AHB_WR_PHY(0x0000069c, 0x3727370F); // ZQ config CPV_APHY cal_ctrl_reg2 P[12:8] N[5:1]    cal_ctrl_reg2[0] [13]set 1
                                        //  CPV_DPHY          cal_ctrl_reg2 P[28:24]N[20:16]  cal_ctrl_reg2[29][21]set 1

    AHB_WR_PHY(0x000006bc, 0x00000000); // 7 [31]
                                        //*************
                                        // IO ODT DS config
                                        //************

  // char ODT_DQ_0_7;
  // char ODTEN_DQ_0_7;
  // unsigned int tmp;
  //
  // BITSET(tmp, 7, 0, vaule);
  // BITSET(tmp, 15, 8, value2);
    

    AHB_WR_PHY(0x000006a0, 0x9B7666DD); // 0
    AHB_WR_PHY(0x000006a4, 0xB7666DD9); // 1
    AHB_WR_PHY(0x000006a8, 0x5A22DD99); // 2
    AHB_WR_PHY(0x000006ac, 0x2DD688B7); // 3
    AHB_WR_PHY(0x000006b0, 0x688B75A2); // 4
    AHB_WR_PHY(0x000006b4, 0xB75A22DD); // 5
    AHB_WR_PHY(0x000006b8, 0x7E66DD99); // 6
    AHB_WR_PHY(0x000006bc, 0x00000457); // 7  calvl_ctrl_reg


   // odt_ds_init();

    //*************
    // 50%  Vref config
    //*************
    // cal_ctrl_reg1[31] HEN1 cal_ctrl[24] HEN0
    // cal_ctrl[29:25]
    // HS
    // 01000
    AHB_WR_PHY(0x000006bc, 0x80000457); // 7 [31]
    AHB_WR_PHY(0x00000698, 0x91000000);
    AHB_WR_PHY(0x000006bc, 0x00000457); // 7 [31]

    //update_for_dq_vref
    BITSET(0x11018000+0x6bc, 31, 31, 1); //CA EN
    BITSET(0x11018000+0x6bc, 24, 24, 1); //High EN
    BITSET(0x11018000+0x6bc, 6, 6, 1); //Low EN
    vref_wr(DQ_VREF);

// LEN   calvl_ctrl_reg_0[12]
// LS4-0 calvl_ctrl_reg_0[17:13]
// 010001
#endif

    AHB_WR_PHY(0x00000000, 0x20410700);
    AHB_WR_PHY(0x00000004, 0x00000000);
    AHB_WR_PHY(0x00000008, 0x00000000);
    AHB_WR_PHY(0x0000000c, 0x00000000);
    AHB_WR_PHY(0x00000010, 0x00000000);
    AHB_WR_PHY(0x00000014, 0x00000000);
    AHB_WR_PHY(0x00000018, 0x00000000);
    AHB_WR_PHY(0x0000001c, 0x00000000);
    AHB_WR_PHY(0x00000020, 0x00000000);
    AHB_WR_PHY(0x00000024, 0x00000000);
    AHB_WR_PHY(0x00000028, 0x00000000);
    AHB_WR_PHY(0x0000002c, 0x00000000);
    AHB_WR_PHY(0x00000030, 0x0000007a); // tinit
    AHB_WR_PHY(0x00000034, 0x00030D40); // tinit3
    AHB_WR_PHY(0x00000038, 0x00000600); // tinit4
    AHB_WR_PHY(0x0000003c, 0x01000600); // tinit5

    AHB_WR_PHY(0x00000040, 0x00000200);
    AHB_WR_PHY(0x00000044, 0x00000200);
    AHB_WR_PHY(0x00000048, 0x00000000);
    AHB_WR_PHY(0x0000004c, 0x1a000200);
    AHB_WR_PHY(0x00000050, 0x0f00000a); // 050 [24:28] 0 --> f ： pcu tccd
    AHB_WR_PHY(0x00000054, 0x18243208);
    AHB_WR_PHY(0x00000058, 0x04002410);
    AHB_WR_PHY(0x0000005c, 0x00002210);
    AHB_WR_PHY(0x00000060, 0x0e000000);
    AHB_WR_PHY(0x00000064, 0x0a0a0020);
    AHB_WR_PHY(0x00000068, 0x000a0a24);
    AHB_WR_PHY(0x0000006c, 0x1b010100);
    AHB_WR_PHY(0x00000070, 0x00000d03);
    AHB_WR_PHY(0x00000074, 0x00000101);
    AHB_WR_PHY(0x00000078, 0x00bb0000);
    AHB_WR_PHY(0x0000007c, 0x00000820);
    AHB_WR_PHY(0x00000080, 0x00001706);
    AHB_WR_PHY(0x00000084, 0x00000000);
    AHB_WR_PHY(0x00000088, 0x00000200);
    AHB_WR_PHY(0x0000008c, 0x000000e0);
    AHB_WR_PHY(0x00000090, 0x0a000001);
    AHB_WR_PHY(0x00000094, 0x0500000a);
    AHB_WR_PHY(0x00000098, 0x001f0403);
    AHB_WR_PHY(0x0000009c, 0x00040003);
    AHB_WR_PHY(0x000000a0, 0x00000007);
    AHB_WR_PHY(0x000000a4, 0x00000000);
    AHB_WR_PHY(0x000000a8, 0x00000000);
    AHB_WR_PHY(0x000000ac, 0x00000000);
    AHB_WR_PHY(0x000000b0, 0x00000000);
    AHB_WR_PHY(0x000000b4, 0x00000000);
    AHB_WR_PHY(0x000000b8, 0x00000000);
    AHB_WR_PHY(0x000000bc, 0x00000000);
    AHB_WR_PHY(0x000000c0, 0x00000000);

#ifdef sg94
    AHB_WR_PHY(0x000000c4, 0x00830124);
    AHB_WR_PHY(0x000000c8, 0x0000001e);
#else
    AHB_WR_PHY(0x000000c4, 0x00430124);
    AHB_WR_PHY(0x000000c8, 0x0000001a);
#endif

    AHB_WR_PHY(0x000000cc, 0x00000010);
    AHB_WR_PHY(0x000000d0, 0x00000000);
    AHB_WR_PHY(0x000000d4, 0x00000000);
    AHB_WR_PHY(0x000000d8, 0x00000000);
    AHB_WR_PHY(0x000000dc, 0x00000000);
    AHB_WR_PHY(0x000000e0, 0x00000000);
    AHB_WR_PHY(0x000000e4, 0x00000000);
    AHB_WR_PHY(0x000000e8, 0x00000000);
    AHB_WR_PHY(0x000000ec, 0x00000000);
    AHB_WR_PHY(0x000000f0, 0x00000000);
    AHB_WR_PHY(0x000000f4, 0x00000000);
    AHB_WR_PHY(0x000000f8, 0x00000000);
    AHB_WR_PHY(0x000000fc, 0x00000000);
    AHB_WR_PHY(0x00000100, 0x00000000);
    AHB_WR_PHY(0x00000104, 0x00000000);
    AHB_WR_PHY(0x00000108, 0x00000000);
    AHB_WR_PHY(0x0000010c, 0x00000000);
    AHB_WR_PHY(0x00000110, 0x00000000);
    AHB_WR_PHY(0x00000114, 0x00025100);
    AHB_WR_PHY(0x00000118, 0x004b0129);
    AHB_WR_PHY(0x0000011c, 0x00000200);
    AHB_WR_PHY(0x00000120, 0x00000040);
    AHB_WR_PHY(0x00000124, 0x00000000);
    AHB_WR_PHY(0x00000128, 0x01030000);
    AHB_WR_PHY(0x0000012c, 0x01ffff0a);
    AHB_WR_PHY(0x00000130, 0x00001111);
    AHB_WR_PHY(0x00000134, 0x00001111);
    AHB_WR_PHY(0x00000138, 0x00010b01);

#ifdef x16bit_half_mode
    AHB_WR_PHY(0x0000013c, 0x01000100);
#else
    AHB_WR_PHY(0x0000013c, 0x00000100); // Reduc
#endif
    AHB_WR_PHY(0x00000140, 0x00000000);
    AHB_WR_PHY(0x00000144, 0x00000000);
    AHB_WR_PHY(0x00000148, 0x00000100);
    AHB_WR_PHY(0x0000014c, 0x00000000);
    AHB_WR_PHY(0x00000150, 0x00000000);
    AHB_WR_PHY(0x00000154, 0x00000000);
    AHB_WR_PHY(0x00000158, 0x00000000);
    AHB_WR_PHY(0x0000015c, 0x00000000);
    AHB_WR_PHY(0x00000160, 0x00000000);
    AHB_WR_PHY(0x00000164, 0x00000000);
    AHB_WR_PHY(0x00000168, 0x00000000);
    AHB_WR_PHY(0x0000016c, 0x00000000);
    AHB_WR_PHY(0x00000170, 0x00000000);
    AHB_WR_PHY(0x00000174, 0x00000000);
    AHB_WR_PHY(0x00000178, 0x00000000);
    AHB_WR_PHY(0x0000017c, 0x00000000);
    AHB_WR_PHY(0x00000180, 0x00000000);
    AHB_WR_PHY(0x00000184, 0x00000000);
    AHB_WR_PHY(0x00000188, 0x00000000);
    AHB_WR_PHY(0x0000018c, 0x00000000);
    AHB_WR_PHY(0x00000190, 0x00000000);
    AHB_WR_PHY(0x00000194, 0x00000000);
    AHB_WR_PHY(0x00000198, 0x04010800);
    AHB_WR_PHY(0x0000019c, 0x01040202);
    AHB_WR_PHY(0x000001a0, 0x06060808);
    AHB_WR_PHY(0x000001a4, 0x00000001);
    AHB_WR_PHY(0x000001a8, 0x02000204);
    AHB_WR_PHY(0x000001ac, 0x02020102);
    AHB_WR_PHY(0x000001b0, 0x00020001);
    AHB_WR_PHY(0x000001b4, 0x00000000);
    AHB_WR_PHY(0x000001b8, 0x00000000);
    AHB_WR_PHY(0x000001bc, 0x00000000);
    AHB_WR_PHY(0x000001c0, 0x00000000);
    AHB_WR_PHY(0x000001c4, 0x0000280d);
    AHB_WR_PHY(0x000001c8, 0x00010100);
    AHB_WR_PHY(0x000001cc, 0x00000000);
    AHB_WR_PHY(0x000001d0, 0x0000000f);
    AHB_WR_PHY(0x000001d4, 0x00001000);
    AHB_WR_PHY(0x000001d8, 0x00000001);
    AHB_WR_PHY(0x000001dc, 0x00000010);
    AHB_WR_PHY(0x000001e0, 0x00000440);
    AHB_WR_PHY(0x000001e4, 0x0556aa00);
    AHB_WR_PHY(0x000001e8, 0x00000000); // close background pattern
    AHB_WR_PHY(0x000001ec, 0x000aa955);
    AHB_WR_PHY(0x000001f0, 0x000556aa);
    AHB_WR_PHY(0x000001f4, 0x000556aa);
    AHB_WR_PHY(0x000001f8, 0x000aa955);
    AHB_WR_PHY(0x000001fc, 0x000aa955);
    AHB_WR_PHY(0x00000200, 0x000556aa);
    AHB_WR_PHY(0x00000204, 0x00001300);
    AHB_WR_PHY(0x00000208, 0x0f000100);
    AHB_WR_PHY(0x0000020c, 0x00040400);
    AHB_WR_PHY(0x00000210, 0x00040400);
    AHB_WR_PHY(0x00000214, 0x00040400);
    AHB_WR_PHY(0x00000218, 0x00040400);
    AHB_WR_PHY(0x0000021c, 0x00040400);
    AHB_WR_PHY(0x00000220, 0x00040400);
    AHB_WR_PHY(0x00000224, 0x00040400);
    AHB_WR_PHY(0x00000228, 0x00040400);
    AHB_WR_PHY(0x0000022c, 0x00011907);
    AHB_WR_PHY(0x00000230, 0x19000119);
    AHB_WR_PHY(0x00000234, 0x01190001);
    AHB_WR_PHY(0x00000238, 0x00011900);
    AHB_WR_PHY(0x0000023c, 0x19000119);
    AHB_WR_PHY(0x00000240, 0x01190001);
    AHB_WR_PHY(0x00000244, 0x00000000);
    AHB_WR_PHY(0x00000248, 0x00000000);
    AHB_WR_PHY(0x0000024c, 0x00001000);

    AHB_WR_PHY(0x00000250, 0x00385c00);
    AHB_WR_PHY(0x00000254, 0x02000200);
    AHB_WR_PHY(0x00000258, 0x02000200);
    AHB_WR_PHY(0x0000025c, 0x0000385c);
    AHB_WR_PHY(0x00000260, 0x000119cc);

#ifdef sg94
    AHB_WR_PHY(0x00000264, 0x00020a12); // tune dfi read lat
#else
    AHB_WR_PHY(0x00000264, 0x00020a0e);
    if (ddr_freq == 150) {
        AHB_WR_PHY(0x00000264, 0x00020a06);
    }
    if (ddr_freq == 54) {
        AHB_WR_PHY(0x00000264, 0x00020a0b);
    }
#endif

    AHB_WR_PHY(0x00000268, 0x00190a03);
    AHB_WR_PHY(0x0000026c, 0x00000000);
    AHB_WR_PHY(0x00000270, 0x00000000);
    AHB_WR_PHY(0x00000274, 0x0000189a);
    AHB_WR_PHY(0x00000278, 0x00000000);
    AHB_WR_PHY(0x0000027c, 0x00000000);
    AHB_WR_PHY(0x00000280, 0x00000000);
    AHB_WR_PHY(0x00000284, 0x00000000);
    AHB_WR_PHY(0x00000288, 0x00000000);
    AHB_WR_PHY(0x0000028c, 0x00000d03);
    AHB_WR_PHY(0x00000290, 0x00000003);
    AHB_WR_PHY(0x00000294, 0x00000000);
    AHB_WR_PHY(0x00000298, 0x00000000);
    AHB_WR_PHY(0x0000029c, 0x00000000);
    AHB_WR_PHY(0x000002a0, 0x00010000);
    AHB_WR_PHY(0x000002a4, 0x00000008);

#ifdef POST_SIM_PATCH
    AHB_WR_PHY(0x00000680, 0x06005806); // [3:0] tune delay for Rptr & ratio if timing
    AHB_WR_PHY(0x00000410, 0x0c22000f); // 28:25 22:20 phase sel, phase detect(setup/hold)
    AHB_WR_PHY(0x00000490, 0x0c22000f); // 28:25
    AHB_WR_PHY(0x00000510, 0x0c22000f); // 28:25
    AHB_WR_PHY(0x00000590, 0x0c22000f); // 28:25
    AHB_WR_PHY(0x00000610, 0x0e22000f); // 0x0e12000f 22:20 phase sel

    AHB_WR_PHY(0x00000454, 0x00000005); // 3:0 dly sel
    AHB_WR_PHY(0x000004d4, 0x00000005); // 3:0
    AHB_WR_PHY(0x00000554, 0x00000005); // 3:0
    AHB_WR_PHY(0x000005d4, 0x00000005); // 3:0

    // for read dqs
    AHB_WR_PHY(0x00000414, 0x14003450); // [31:24] gate fine delay, [5:0] rd lvl
    AHB_WR_PHY(0x00000494, 0x14003450); // rd lvl
    AHB_WR_PHY(0x00000514, 0x14003450); // rd lvl
    AHB_WR_PHY(0x00000594, 0x14003450); // rd lvl
#endif

    // for eco swap
    AHB_WR_PHY(0x2a8, 0x0A1E);
    AHB_WR_PHY(0x2d4, 0x0B0C0D0E);
    AHB_WR_PHY(0x2D8, 0x0F);
    AHB_WR_PHY(0x2DC, 0x12);
    AHB_WR_PHY(0x2E0, 0x10);
    AHB_WR_PHY(0x2E4, 0x11);
    AHB_WR_PHY(0x2E8, 0x13);
    AHB_WR_PHY(0x2EC, 0x0);
    AHB_WR_PHY(0x2F0, 0x1);
    AHB_WR_PHY(0x2F4, 0x2);
    AHB_WR_PHY(0x2F8, 0x3);
    AHB_WR_PHY(0x2FC, 0x4);
    AHB_WR_PHY(0x300, 0x5);
    AHB_WR_PHY(0x304, 0x8);
    AHB_WR_PHY(0x308, 0x6);
    AHB_WR_PHY(0x30C, 0x7);
    AHB_WR_PHY(0x310, 0x9);
    AHB_WR_PHY(0x314, 0x01234567); //
    AHB_WR_PHY(0x318, 0x89ABCDEF); //
    AHB_WR_PHY(0x31C, 0xfedcba98); //
    AHB_WR_PHY(0x320, 0x76543210); //
    //=======================================================================
    // 第四阶段：DDR初始化和训练流程
    // 执行DDR PHY初始化，并根据配置执行各种训练：
    // - CA训练 (Command/Address training)
    // - Gating训练 (Gate training)
    // - 写电平训练 (Write leveling)
    // - 读电平训练 (Read leveling)
    //=======================================================================

    if (lpddr3_ca_train) {
        AHB_WR_PHY(0x00000204, 0x00011300); // calvl mode
        AHB_WR_PHY(0x0000029c, 0x00000100); // calvl en
    }

    AHB_WR_PHY(0x00000000, 0x20410701);  // PI_START
    AHB_WR_CTRL(0x00000320, 0x00000000); // SW_DONE
    AHB_WR_CTRL(0x000001b0, 0x00000041); // DFIMISC
    AHB_WR_CTRL(0x00000320, 0x00000001); // SWCTL
    AHB_CHECK_CTRL(0x000001bc, 0x00000001, 0x00000001);
    AHB_CHECK_CTRL(0x00000004, 0x00000007, 0x00000001);
    AHB_CHECK_PHY(0x00000150, 0x00000010, 0x00000010); // PHYREADY

    // AHB_WR_PHY(0x408, 0x100100d8); // gate_end[4:3] 0x3
    // AHB_WR_PHY(0x488, 0x100100d8); // gate_end[4:3] 0x3 //gate  enze
    // AHB_WR_PHY(0x508, 0x100100d8); // gate_end[4:3] 0x3
    // AHB_WR_PHY(0x588, 0x100100d8); // gate_end[4:3] 0x3

    //-----------------------------------------------------------------------
    // Gating训练流程
    // 如果启用gating训练，则调整gate_end参数
    //-----------------------------------------------------------------------
    if (lpddr3_gating_train) {
        AHB_WR_PHY(0x408, 0x300100c0); // gate_end[4:3] 0x3
        AHB_WR_PHY(0x488, 0x300100c0); // gate_end[4:3] 0x3
        AHB_WR_PHY(0x508, 0x300100c0); // gate_end[4:3] 0x3
        AHB_WR_PHY(0x588, 0x300100c0); // gate_end[4:3] 0x3
    }

    AHB_WR_PHY(0x0000042c, 0x030c87cf); // BDL
    AHB_WR_PHY(0x000004ac, 0x030c87cf); // BDL
    AHB_WR_PHY(0x0000052c, 0x030c87cf); // BDL
    AHB_WR_PHY(0x000005ac, 0x030c87cf); // BDL

    if (lpddr3_ca_train) {
        // compensate for cycle boundary jitter, minus 1~2 step
        rdata = AHB_RD_PHY(0x00000680 + 3 * 4);

        // bit 25: calvl_clkperiod_dly
        if (rdata & (1u << 25)) {
            // read wr_dqs (bits [23:16])
            rdata = AHB_RD_PHY(0x00000614);
            wr_dqs = (rdata >> 16) & 0xFF;

            // for 2133, code 0x13
            if (wr_dqs > 248) {
                wr_dqs = 228;
            }

            // clear old bits [23:16] and write back new wr_dqs
            rdata = (rdata & ~(0xFFu << 16)) | (wr_dqs << 16);
            AHB_WR_PHY(0x00000614, rdata);

            // toggle up_pls bit 10
            rdata = AHB_RD_PHY(0x00000680 + 16 * 4);
            rdata &= ~(1u << 10); // clear
            AHB_WR_PHY(0x00000680 + 16 * 4, rdata);

            rdata |= (1u << 10); // set
            AHB_WR_PHY(0x00000680 + 16 * 4, rdata);

            // read valid dly (bits [3:0]) and +1
            rdata = AHB_RD_PHY(0x00000680);
            rdata = (rdata & ~0xFu) | (((rdata & 0xFu) + 1) & 0xFu);
            AHB_WR_PHY(0x00000680, rdata);
        }

        // init MR again by controller (phy auto init maybe err for cycle boundary issue), for CA clk err, 2133
        AHB_WR_CTRL(0x00000320, 0x00000000);                // SW_DONE
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRSTAT, mr_wr_busy
        AHB_WR_CTRL(0x00000014, (0xa << 8) | 0xff);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000);
        AHB_WR_CTRL(0x00000014, (0x2 << 8) | 0x1e);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRCTRL1
        AHB_WR_CTRL(0x00000014, (0x3 << 8) | 0x10);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRCTRL1
        AHB_WR_CTRL(0x00000014, (0xb << 8) | 0x00);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRCTRL1
        AHB_WR_CTRL(0x00000014, (0x10 << 8) | 0x00);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRCTRL1
        AHB_WR_CTRL(0x00000014, (0x11 << 8) | 0x00);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRCTRL1
        AHB_WR_CTRL(0x00000014, (0x1 << 8) | 0x83);
        AHB_WR_CTRL(0x00000010, 0x80000000);
        AHB_CHECK_CTRL(0x00000018, 0x00000001, 0x00000000); // MRCTRL1
        AHB_WR_CTRL(0x00000320, 0x00000001);                // SW_DONE

        // AHB_WR_PHY(0x000001e0, 0x00000440); // calvl_req
        // AHB_WR_PHY(0x00000138, 0x00010b01); // pi on bus
    }

    //-----------------------------------------------------------------------
    // 写电平训练流程 (Write Leveling Training)
    // 如果启用写电平训练，则执行相应的寄存器配置和训练流程
    //-----------------------------------------------------------------------
    rdata = AHB_RD_PHY(0x00000414);

    mc_printf("address 414 rdata is  %x ", rdata); // enze

    if (lpddr3_wrlvl_train) {
        AHB_WR_PHY(0x00000138, 0x80010b01); // pi on bus
        AHB_CHECK_PHY(0x00000150, 0x10000000, 0x10000000);

        AHB_WR_PHY(0x1c4, 0x0001280d);      // [16] wrlvl en
        AHB_WR_PHY(0x1c8, 0x00010100);      // [16] wrlvl mode
        AHB_WR_PHY(0x1c0, 0x00010000);      // [16] wrlvl req
        AHB_WR_PHY(0x00000154, 0x00040000); // clr int
        AHB_CHECK_PHY(0x00000150, 0x00040000, 0x00040000);
        // to do: update for 1us delay

        AHB_WR_PHY(0x1c0, 0x00000000); // [16] wrlvl req
        // AHB_WR_PHY(0x00000138, 0x00010b01); // pi on bus
    }
    rdata = AHB_RD_PHY(0x00000414);

    mc_printf("address 414 rdata is  %x ", rdata); // enze
    if (lpddr3_gating_train) {
        // AHB_WR_PHY(0x408, 0x100100d8); // gate_end[4:3] 0x3

        AHB_WR_PHY(0x00000138, 0x80010b01); // pi on bus
        AHB_CHECK_PHY(0x00000150, 0x10000000, 0x10000000);

        AHB_WR_PHY(0x27c, 0x00010000);                  // reserve_159 [16] rd gate en
        AHB_WR_PHY(0x1d8, 0x00000001);                  // reserve_118 [0] rdlvl gate mode
        AHB_WR_PHY(0x1d0, 0x0100000f);                  // reserve_116 [24] rdlvl gate req
        AHB_WR_PHY(0x00000154, 0x00040000);             // clr int
        AHB_CHECK_PHY(0x00150, 0x00040000, 0x00040000); // [18] lvl_done
        AHB_CHECK_PHY(0x00150, 0x00010000, 0x00010000); // [16] rdlvl_gate_req
        // to do: update for 1us delay
        AHB_CHECK_PHY(0x00434, 0x0000000f, 0x00000000); // 
        AHB_CHECK_PHY(0x004B4, 0x0000000f, 0x00000000); // 
        AHB_CHECK_PHY(0x00534, 0x0000000f, 0x00000000); // 
        AHB_CHECK_PHY(0x005B4, 0x0000000f, 0x00000000); // 

        AHB_WR_PHY(0x1d0, 0x0000000f);
        // AHB_WR_PHY(0x00000138, 0x00010b01); // pi on bus
    }

    //-----------------------------------------------------------------------
    // 读电平训练流程 (Read Leveling Training)
    // 如果启用读电平训练，则执行相应的寄存器配置和训练流程
    //-----------------------------------------------------------------------
    if (lpddr3_rdlvl_train) {
        AHB_WR_PHY(0x00000138, 0x80010b01); // pi on bus
        AHB_CHECK_PHY(0x00000150, 0x10000000, 0x10000000);

        AHB_WR_PHY(0x1d4, 0x01001000);                  // reserve_118 [24] rdlvl mode
        AHB_WR_PHY(0x27c, 0x00000100);                  // reserve_159 [8] rd lvl en
        AHB_WR_PHY(0x1d0, 0x0001000f);                  // reserve_116 [16] rdlvl req
        AHB_WR_PHY(0x00000154, 0x00040000);             // clr int
        AHB_CHECK_PHY(0x00150, 0x00040000, 0x00040000); // [18] lvl_done

        AHB_WR_PHY(0x1d0, 0x0000000f); // reserve_116 [16] rdlvl req
        // AHB_WR_PHY(0x00000138, 0x00010b01); // pi on bus
    }
    if (lpddr3_rdlvl_train) {
        rdata = AHB_RD_PHY(0x00000494);
      //  AHB_WR_PHY(0x0494, (rdata & 0xffffff00) | 0x40  ); // rdlvl base
        AHB_WR_PHY(0x0414, (rdata & 0xffffff00) | 0x30); // rdlvl base
        AHB_WR_PHY(0x0494, (rdata & 0xffffff00) | 0x30); // rdlvl base
        AHB_WR_PHY(0x0514, (rdata & 0xffffff00) | 0x30); // rdlvl base  0828 21：25
        AHB_WR_PHY(0x0594, (rdata & 0xffffff00) | 0x30); // rdlvl base
        rdata = AHB_RD_PHY(0x00002200);
        AHB_WR_PHY(0x2200, rdata | 0x1 << 4); // reserve_116 [16] rdlvl req
    
    }
    //=======================================================================
    // LPDDR3初始化完成
    // 恢复PHY总线配置，完成整个DDR初始化流程
    //=======================================================================
    AHB_WR_PHY(0x00000138, 0x00010b01); // pi on bus

    //------enze----
 //  AHB_WR_PHY(0x00000410, 0x0812000f); // [28:25] pop dly
 //  AHB_WR_PHY(0x00000490, 0x0812000f); // [28:25] pop dly
 //  AHB_WR_PHY(0x00000510, 0x0812000f); // [28:25] pop dly
 //  AHB_WR_PHY(0x00000590, 0x0812000f); // [28:25] pop dly
 //
 //  AHB_WR_PHY(0x00000454, 0x00000003); // [3:0] rd dly
 //  AHB_WR_PHY(0x000004d4, 0x00000003); // [3:0] rd dly
 //  AHB_WR_PHY(0x00000554, 0x00000003); // [3:0] rd dly
 //  AHB_WR_PHY(0x000005d4, 0x00000003); // [3:0] rd dly
 //
 //  AHB_WR_PHY(0x00000680, 0x06005804); // [3:0] read data valid dly

    // 这4个寄存器相当于 4 个 Slice 的 Select 开关
    // bit[31:31] 1 = 来源于寄存器，0 = 来源于状态机（现在不用）
    if (0 == lpddr3_gating_train)
    {
        AHB_WR_PHY(0x0000042c, 0x830c87c1); // enze gate cfg enable
        AHB_WR_PHY(0x000004ac, 0x830c87c1); // enze gate cfg enable
        AHB_WR_PHY(0x0000052c, 0x830c87c1); // enze gate cfg enable
        AHB_WR_PHY(0x000005ac, 0x830c87c1); // enze gate cfg enable
    }

    // 进行 Gate Scan
    //test01();

    check_list_print();
}

void Hv_Ddr_Init(void)
{
    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> ####lpddr3_init1 ");
    lpddr3_init();
    while(1);
    //Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> ####lpddr3_init2 ");
    //lpddr3_init();
}
